#-*- coding: UTF-8 -*-
"""
Lme 封装的 sqlite3 常用方法。
"""

import sqlite3
import clr
clr.AddReference("LunarMarkdownEditor")
from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils.NPOIHelp import *


__all__ = ['打开数据库', '创建数据库', '连接数据库']

def 打开数据库(dbPath):
    connect = 数据库连接(sqlite3.connect(dbPath))
    connect.取数据库游标()
    return connect

def 创建数据库(dbPath):
    connect = 数据库连接(sqlite3.connect(dbPath))
    connect.取数据库游标()
    return connect

def 连接数据库(dbPath):
    connect = 数据库连接(sqlite3.connect(dbPath))
    connect.取数据库游标()
    return connect

sqlite3_keyword_list = ['ABORT', 'ACTION', 'ADD', 'AFTER', 'ALL', 'ALTER', 'ALWAYS', 'ANALYZE', 'AND', 'AS', 'ASC', 'ATTACH', 'AUTOINCREMENT', 'BEFORE', 'BEGIN', 'BETWEEN', 'BY', 'CASCADE', 'CASE', 'CAST', 'CHECK', 'COLLATE', 'COLUMN', 'COMMIT', 'CONFLICT', 'CONSTRAINT', 'CREATE', 'CROSS', 'CURRENT', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'DATABASE', 'DEFAULT', 'DEFERRABLE', 'DEFERRED', 'DELETE', 'DESC', 'DETACH', 'DISTINCT', 'DO', 'DROP', 'EACH', 'ELSE', 'END', 'ESCAPE', 'EXCEPT', 'EXCLUDE', 'EXCLUSIVE', 'EXISTS', 'EXPLAIN', 'FAIL', 'FILTER', 'FIRST', 'FOLLOWING', 'FOR', 'FOREIGN', 'FROM', 'FULL', 'GENERATED', 'GLOB', 'GROUP', 'GROUPS', 'HAVING', 'IF', 'IGNORE', 'IMMEDIATE', 'IN', 'INDEX', 'INDEXED', 'INITIALLY', 'INNER', 'INSERT', 'INSTEAD', 'INTERSECT', 'INTO', 'IS', 'ISNULL', 'JOIN', 'KEY', 'LAST', 'LEFT', 'LIKE', 'LIMIT', 'MATCH', 'MATERIALIZED', 'NATURAL', 'NO', 'NOT', 'NOTHING', 'NOTNULL', 'NULL', 'NULLS', 'OF', 'OFFSET', 'ON', 'OR', 'ORDER', 'OTHERS', 'OUTER', 'OVER', 'PARTITION', 'PLAN', 'PRAGMA', 'PRECEDING', 'PRIMARY', 'QUERY', 'RAISE', 'RANGE', 'RECURSIVE', 'REFERENCES', 'REGEXP', 'REINDEX', 'RELEASE', 'RENAME', 'REPLACE', 'RESTRICT', 'RETURNING', 'RIGHT', 'ROLLBACK', 'ROW', 'ROWS', 'SAVEPOINT', 'SELECT', 'SET', 'TABLE', 'TEMP', 'TEMPORARY', 'THEN', 'TIES', 'TO', 'TRANSACTION', 'TRIGGER', 'UNBOUNDED', 'UNION', 'UNIQUE', 'UPDATE', 'USING', 'VACUUM', 'VALUES', 'VIEW', 'VIRTUAL', 'WHEN', 'WHERE', 'WINDOW', 'WITH', 'WITHOUT']

class 数据库游标:
    def __init__(self, cursor, connect):
        self._游标体 = cursor
        self._数据库连接 = connect

    def 执行语句(self, sql, data_tuple_or_dict = None):
        if data_tuple_or_dict == None:
            self._游标体.execute(sql)
        else:
            self._游标体.execute(sql, data_tuple_or_dict)
        return self

#    实测 cursor.executescript() 方法会陷入卡死
#    def 执行脚本(self, sql):
#        self._游标体.executescript(sql)
#        return self

    def 是否合法标识符(self, id_txt, validate_chinese = False):
        '''
        除中文字符外，只允许以字母、数字、下划线组成标识符（用于表名、字段名等），且不能以数字开头！
        是否允许中文，看 validate_chinese 的值，默认为 False。
        '''        
        if id_txt == None or len(id_txt) <= 0:
            return False
        validate = 纯文本处理器.是否合法标识符(id_txt, validate_chinese)
        if validate == False:
            return False
        if id_txt.upper() in sqlite3_keyword_list:
            return False
        else:
            return True

    def 导入文本数据表(self, table_name, data_text_table):
        if data_text_table == None or len(data_text_table) <= 0:
            raise ValueError("要导入的源数据表不能为空。")
        if table_name == None or len(table_name) <= 0:
            raise ValueError("表名不能为空。")
        if self.是否合法标识符(table_name, False) == False:
            raise ValueError("“" + table_name + "” 不适合作为表名。表名只能使用半角英文字母、数字或下划线(_)字符，且不能以数字开头。网上说可以支持汉字，但实测效果不佳。")
        if table_name.upper() in sqlite3_keyword_list:
            raise ValueError("“" + table_name + "” 不适合作为表名。因为它是 sqlite3 的保留关键词。")
        field_names = data_text_table.取字段名元组()
        if field_names == None or len(field_names) <= 0:
            raise ValueError("要导入的数据表没有字段名行。")
        for field_name in field_names:
            if field_name == None or len(field_name) <= 0:
                raise ValueError("字段名不能为空。")
            if self.是否合法标识符(field_name, False) == False:
                raise ValueError("“" + field_name  + "” 不适合作为字段名。字段名只能使用半角英文字母、数字或下划线(_)字符，且不能以数字开头。网上说可以支持汉字，但实测效果不佳。")
            if field_name in sqlite3_keyword_list:
                raise ValueError("“" + field_name  + "” 不适合作为字段名。因为它是 sqlite3 的保留关键词。")
        sql = "CREATE TABLE IF NOT EXISTS " + table_name + " (" + " TEXT, ".join(field_names) + ")"
        self._游标体.execute(sql)
        data_list = []
        for row in data_text_table:
            data_list.append(row.数据元组)
        questions = "?," * len(field_names)
        questions = questions.rstrip(', ')
        insert_sql = "INSERT INTO " + table_name + " (" + ", ".join(field_names) + ") VALUES (" + questions + ")"
        self._游标体.executemany(insert_sql, data_list)
        if self._数据库连接 != None:
            self._数据库连接.提交事务()
        return self

    def 导入文字表(self, table_name, text_table):
        if text_table == None:
            raise ValueError("要导入的文字表不能为空。")
        if text_table.文字表头行集 == None or len(text_table.文字表头行集) <= 0:
            raise ValueError("要导入的文字表表头部分不能为空。")
        if text_table.文字表体行集 == None or len(text_table.文字表体行集) <= 0:
            raise ValueError("要导入的文字表表体部分不能为空。")
        return self.导入文本数据表(table_name, text_table.到文本数据表())

    def 导入二维文字表(self, table_name, text_table):
        return self.导入文字表(table_name, text_table)

    def 批量执行(self, sql, tuples_in_list):
        self._游标体.executemany(sql, tuples_in_list)
        return self

    def 取查询结果(self, field_list = None):
        record_list = self._游标体.fetchall()
        if field_list == None or len(field_list) <= 0:
            return record_list
        else:
            if record_list == None or len(record_list) <= 0:
                return None
            return 文本数据表(field_list, record_list)
    
    def 提交事务(self):
        if self._数据库连接 != None:
            self._数据库连接.提交事务()
        return self

    def 回滚事务(self):
        if self._数据库连接 != None:
            self._数据库连接.回滚事务()
        return self

    def 关闭数据库(self):
        if self._数据库连接 != None:
            self._数据库连接.关闭数据库()
        return self

    def 取字段列表(self, table_name):
        self._游标体.execute(f"PRAGMA table_info({table_name})")
        columns = self._游标体.fetchall()
        return [column[1] for column in columns]

    def 取字段信息(self, table_name):
        self._游标体.execute(f"PRAGMA table_info({table_name})")
        columns = self._游标体.fetchall()
        return columns

    def 关闭游标(self):
        self._游标体.close()



class 数据库连接:
    def __init__(self, connect):
        self._连接体 = connect

    def 取数据库游标(self):
        if hasattr(self, '_数据库游标') == False or self._数据库游标 == None:
            self._数据库游标 = 数据库游标(self._连接体.cursor(), self)
            return self._数据库游标
        else:
            return self._数据库游标

    def 是否合法标识符(self, id_txt, validate_chinese = False):
        '''
        除中文字符外，只允许以字母、数字、下划线组成标识符（用于表名、字段名等），且不能以数字开头！
        是否允许中文，看 validate_chinese 的值，默认为 False。
        '''        
        if id_txt == None or len(id_txt) <= 0:
            return False
        validate = 纯文本处理器.是否合法标识符(id_txt, validate_chinese)
        if validate == False:
            return False
        if id_txt.upper() in sqlite3_keyword_list:
            return False
        else:
            return True

    def 导入文本数据表(self, table_name, data_text_table):
        _游标 = self.取数据库游标()
        if _游标 != None:
            _游标.导入文本数据表(table_name, data_text_table)
        return self
    
    def 导入文字表(self, table_name, text_table):
        if text_table == None:
            raise ValueError("要导入的文字表不能为空。")
        if text_table.文字表头行集 == None or len(text_table.文字表头行集) <= 0:
            raise ValueError("要导入的文字表表头部分不能为空。")
        if text_table.文字表体行集 == None or len(text_table.文字表体行集) <= 0:
            raise ValueError("要导入的文字表表体部分不能为空。")
        return self.导入文本数据表(table_name, text_table.到文本数据表())

    def 导入二维文字表(self, table_name, text_table):
        return self.导入文字表(table_name, text_table)

    def 执行语句(self, sql, data_tuple_or_dict = None):
        _游标 = self.取数据库游标()
        if _游标 != None:
            if data_tuple_or_dict == None:
                _游标.执行语句(sql)
            else:
                _游标.执行语句(sql, data_tuple_or_dict)
        return self

#    实测 cursor.executescript() 方法会陷入卡死
#    def 执行脚本(self, sql):
#        _游标 = self.取数据库游标()
#        if _游标 != None:
#            _游标.执行脚本(sql)
#        return self

    def 批量执行(self, sql, tuples_in_list):
        _游标 = self.取数据库游标()
        if _游标 != None:
            _游标.批量执行(sql, tuples_in_list)
        return self

    def 取查询结果(self, field_list = None):
        _游标 = self.取数据库游标()
        if _游标 != None:
            if field_list == None or len(field_list) <= 0:
                return _游标.取查询结果()
            else:
                record_list = self.取查询结果()
                if field_list == None or len(field_list) <= 0:
                    return None
                if record_list == None or len(record_list) <= 0:
                    return None
                return 文本数据表(field_list, record_list)
        return None

    def 提交事务(self):
        self._连接体.commit()
        return self

    def 回滚事务(self):
        self._连接体.rollback()
        return self

    def 关闭数据库(self):
        _游标 = self.取数据库游标()
        if _游标 != None:
            _游标.关闭游标()
        self._连接体.close()
        return self

    def 取字段列表(self, table_name):
        _游标 = self.取数据库游标()
        if _游标 != None:
            return _游标.取字段列表(table_name)
        else:
            return None
            
    def 取字段信息(self, table_name):
        _游标 = self.取数据库游标()
        if _游标 != None:
            return _游标.取字段信息(table_name)
        else:
            return None

